from django.db import models
from django.contrib.auth.models import User
import barcode
from barcode.writer import ImageWriter
from festivalrock.settings import MEDIA_ROOT
from festivalrock.utils import CurrencyField
from datetime import date, timedelta
from decimal import Decimal
from django.template.defaultfilters import length
import datetime
EAN = barcode.get_barcode_class('ean13')

RESERVADA = 'reservada'
DISPONIBLE = 'disponible'
BLOQUEADA = 'bloqueada'
ESTADO_BUTACA = (
    (BLOQUEADA, 'bloqueada'),
    (RESERVADA, 'reservada'),
    (DISPONIBLE, 'disponible'),
)
MAYORES = 'mayores'
MENORES = 'menores'
JUBILADOS = 'jubilados'
TIPO_ENTRADA = {MAYORES:1, MENORES:2, JUBILADOS:3}
CATEGORIA_BANDA = (1, 2, 3, 4)
ADICIONAL_CATEGORIA_BANDA = { 1 : 0, 2 : 50, 3 : 100, 4 : 200 }

class Banda(models.Model):
    nombre =  models.CharField(unique=True,max_length=50)
    categoria = models.IntegerField()
    
    def getCategoria(self):
        return self.categoria
    
    def getAdicionalPorCategoria(self):
        return ADICIONAL_CATEGORIA_BANDA[self.getCategoria()]
    
    def __str__(self):
        return self.nombre.__str__()

class Presentacion(models.Model):
    horaInicio =  models.TimeField()
    horaFin =  models.TimeField()
    banda = models.ForeignKey(Banda)

    def getBanda(self):
        return self.banda
    
    def getFecha(self):
        return self.fecha
    
    def getHoraInicio(self):
        return self.horaInicio
    
    def getAdicionalPorCategoria(self):
        banda = self.getBanda()
        return banda.getAdicionalPorCategoria()
    
    def __str__(self):
        bandas = Banda.objects.filter(presentacion__id=self.id)
        bandas_str = [banda.__str__() for banda in bandas]
        return bandas_str.__str__()
    
class PerfilUsuario(models.Model):
    user = models.OneToOneField(User)
    nombre = models.CharField(max_length=50)
    tipoUsuario = models.CharField(max_length=1)
    def __str__(self):
        return self.nombre.__str__()

class Butaca(models.Model):   
    numero = models.IntegerField()
    estado = models.CharField(max_length=200, choices=ESTADO_BUTACA, default=DISPONIBLE)
    vendedor = models.ForeignKey(User,blank=True,null=True)
    
    def getNumero(self):
        return self.numero
    
    def getEstado(self):
        return self.estado
    
    def desbloquear(self):
        if self.estado == BLOQUEADA:
            self.estado = DISPONIBLE
            self.save()
    
    def bloquear(self,user):
        if self.estado == DISPONIBLE:
            self.estado = BLOQUEADA
            self.vendedor = user
            self.save()
            
    def reservar(self):
        if self.estado == BLOQUEADA:
            self.estado = RESERVADA
            self.save()
            return True
        return False
    
    def calcularImporteEntradaBase(self):
        sector = self.getSector()
        return sector.calcularImporteEntradaBase()
    
    def adquirir(self,descuento,vendedor):
        if self.reservar():
            zero = Decimal(0.00)
            ticket=Venta.objects.create(butaca=self,
                                         importeDescuento=zero,
                                         importeBruto=self.getSector().importeEntradaBase,
                                         importeNeto=zero,
                                         importeDescuentoAnticipada=zero,
                                         vendedor=vendedor)
            descuentoAnticipada=DescuentoAnticipada.objects.get(presentacion=self.getSector().presentacion)
            ticket.calcularDescuentos(descuento,descuentoAnticipada)
            ticket.calcularImportes()
            ticket.save()
            fullName= ticket.generarCodigoBarra()
            print fullName
            self.save()
            return ticket
        else:
            return Venta.objects.get(butaca=self)
    
    def getSector(self):
        return Sector.objects.get(filas__butacas__id=self.id)
    
    def resumenVenta(self):
        sector = self.getSector()
        bandas = Banda.objects.filter(presentacion=sector.presentacion)
        descuentoAnticipada = DescuentoAnticipada.objects.get(presentacion=sector.presentacion)
        return (sector.presentacion.festival,sector.presentacion.fecha,sector,bandas,descuentoAnticipada.calcularDescuento())
    
    def __str__(self):
        return self.numero.__str__()

class Fila(models.Model):
    numero = models.IntegerField()
    butacas = models.ManyToManyField(Butaca)
    
    def getNumero(self):
        return self.numero
    
    def getButacas(self):
        return self.butacas
    
    def __str__(self):
        return self.numero.__str__()
        
class Sector(models.Model):
    nombre =  models.CharField(unique=True,max_length=20)
    color = models.CharField(max_length=10)
    importeEntradaBase = CurrencyField(max_digits=10, decimal_places=2, blank=True)
    filas = models.ManyToManyField(Fila)
    presentacion = models.ForeignKey(Presentacion)
    
    def getNombre(self):
        return self.nombre
    
    def getColor(self):
        return self.color
    
    def getImporteEntradaBase(self):
        return self.importeEntradaBase
    
    def getFilas(self):
        return self.filas
    
    def getCantidadFilas(self):
        return length(self.filas)

    def getCantidadButacas(self, fila):
        return length(fila.getButacas())
        
    def obtenerBandas(self):
        return Banda.objects.filter(presentacion=self.presentacion)
    
    def populate(self, cantidadFilas, cantidadButacas):
        if cantidadFilas :
            for nroFila in range(cantidadFilas):
                fila = Fila.objects.create(numero=nroFila)
                for nroButaca in range(cantidadButacas):
                    butaca = Butaca.objects.create(numero=nroButaca)
                    fila.butacas.add(butaca)
                fila.save()
                self.filas.add(fila)
            self.save()
    
    def __str__(self):
        return self.getNombre().__str__() + " - $" + self.getImporteEntradaBase().__str__()

class Noche(models.Model):
    nombre =  models.CharField(max_length=20)
    fecha = models.DateField()
    presentaciones = models.ManyToManyField(Presentacion)
    sectores = models.ManyToManyField(Sector)
    
    def getPresentaciones(self):
        return self.presentaciones.all()
    
    def agregarPresentacion(self, presentacion):
        self.presentaciones.add(presentacion)
        
    def agregarSector(self, sector):
        self.sectores.add(sector)
    
    def __str__(self):
        return self.fecha.__str__()
    
    def getAdicionalPorCategoria(self):
        adicionalPorCategoria = 0
        for presentacion in self.getPresentaciones():
            adicionalPorCategoria += presentacion.getAdicionalPorCategoria()
        return  adicionalPorCategoria
    

class Festival(models.Model):
    nombre =  models.CharField(unique=True,max_length=50)
    noches = models.ForeignKey(Noche)
    fechaInicio = models.DateField(default=datetime.datetime.now)
    duracion = models.SmallIntegerField()
    
    def getNombre(self):
        return self.nombre
    
    def getNoches(self):
        return self.noches.all()
        
    def getFechaInicio(self):
        return self.fechaInicio
    
    def getDuracion(self):
        return self.duracion
    
    def getPresentaciones(self):
        presentaciones=()
        for noche in self.getNoches():
            presentaciones.add(noche.getPresentaciones())
        return presentaciones
    
    def __str__(self):
        return self.nombre.__str__()
    
class Descuento(models.Model):
    nombre = models.CharField(max_length=20)
    porcentaje = models.DecimalField(max_digits=4, decimal_places=2)
    
    def calcularDescuento(self, valorBase):
        return valorBase * self.porcentaje / 100
    
    def __str__(self):
        return self.nombre + '-' + self.porcentaje.__str__() + ' %'
    
class DescuentoAnticipada(Descuento):
    diasAnticipados = models.IntegerField()
    presentacion = models.ForeignKey(Presentacion)

    def calcularDescuento(self, valorBase):
        fechaFinAnticipada = self.presentacion.getFecha - timedelta(days=self.diasAnticipados)
        if date.today() <= fechaFinAnticipada:
            self.porcentaje = 10
        return valorBase * self.porcentaje / 100
    
    
class Entrada(models.Model):
    presentacion = models.ForeignKey(Presentacion)
    descuento = models.ForeignKey(Descuento)
    porcentajeDescuento = models.DecimalField(max_digits=4, decimal_places=2)
    codigoBarra = models.CharField(max_length=20)
    
    def calcularDescuento(self):
        return self.descuento.calcularDescuento()
    
    def generarCodigoBarra(self):
        codigo = self.id.__str__() + self.butaca.__str__() + int(self.importeNeto).__str__() 
        ean = EAN(u'' + codigo, writer=ImageWriter())
        self.codigoBarra = codigo
        self.save()
        return ean.save(MEDIA_ROOT + "/" +codigo)

class EntradaMenores(Entrada):
    
    def __init__(self):
        self.porcentajeDescuento = 15
 

class EntradaMayores(Entrada):

    def __init__(self):
        self.porcentajeDescuento = 0

class EntradaJubilados(Entrada):
    
    def __init__(self):
        self.porcentajeDescuento = 0
        
    def calcularDescuento(self, valorBase):
        if valorBase > 100:
            self.porcentaje = 20
        else:
            if valorBase > 50:
                return 10
        
        return self.descuento.calcularDescuento(self.porcentaje)

class Venta(models.Model):
    butaca = models.OneToOneField(Butaca)
    entradas = models.ForeignKey(Entrada)
    vendedor =  models.OneToOneField(PerfilUsuario)
    
    def calcularImporteEntrada(self, butaca):
        valorBase = butaca.calcularImporteEntradaBase()
        return valorBase + self.calcularValorExtraPorNoche() - self.calcularDescuentos(valorBase)
    
    def calcularValorExtraPorNoche(self):
        banda = self.presentacion.getBanda()
        return banda.getAdicionalPorCategoria()
    
    def calcularDescuentos(self, valorBase):
        descuentoTipoPersona = self.entradas.calcularDescuento(valorBase)
        return DescuentoAnticipada.calcularDescuento(valorBase) + descuentoTipoPersona

class PuntoVenta(models.Model):
    nombre =  models.CharField(max_length=20)
    usuario = models.ManyToManyField(PerfilUsuario)  
    festivales = models.ManyToManyField(Festival) 
    
    def agregarFestival(self, festival):
        self.festivales.add(festival)
        
    def agregarVendedor(self, vendedor):
        self.usuario.add(vendedor)
        
    def getPresentacionesDelFestival(self, id_festival):
        festival = self.getFestival(id_festival)
        return festival[0].getPresentaciones()
    
    def getFestival(self, id_festival):
        return Festival.objects.filter(id=id_festival)
    
    def getFestivales(self):
        return self.festivales
    
    def __str__(self):
        return self.nombre.__str__()

class CentroDeVenta(models.Model):
    nombre =  models.CharField(max_length=20)
    puntosDeVenta = models.ForeignKey(PuntoVenta)
    
    def getPuntosDeVenta(self):
        return self.puntosDeVenta
    
class ButacaNoDisponibleException(Exception):
    def __init__(self, valor):
        self.valor = valor
    def __str__(self):
        return "ButacaNoDisponible " + str(self.valor)
        